package cn.edu.cug.cs.gtl.docdb.core;

import cn.edu.cug.cs.gtl.common.Identifier;
import cn.edu.cug.cs.gtl.io.Storable;
import cn.edu.cug.cs.gtl.io.storage.StorageManager;
import org.hsqldb.lib.DataOutputStream;

import java.io.*;
import java.util.Arrays;

/**
 * 采用存储系统StorageManager进行存储管理，每个DocData对应SM中的一个Entry,具有唯一的开始页面ID
 */
public class DocRaw implements Storable {
    protected Identifier internalIdentifier; //文档的内部编号，供计算机使用,和DocMeta进行连接
    protected byte [] rawData;//文档的原始二进制数据
    protected byte [] attachments;//文档的附件的二进制数据

    public DocRaw()   {
        internalIdentifier = Identifier.create();
        rawData = null;
        attachments = null;
    }


    /**
     *
     * @param storageManager
     * @param internalIdentifier
     * @return
     * @throws Exception
     */
    public static DocRaw read(StorageManager storageManager, Identifier internalIdentifier) throws Exception {
        DocRaw docData = new DocRaw();
        docData.internalIdentifier = Identifier.create();
        docData.internalIdentifier.copyFrom(internalIdentifier);
        byte[] bytes = storageManager.loadByteArray(internalIdentifier);
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);
        int c = dataInputStream.readInt();
        if(c>0) {
            docData.rawData = new byte[c];
            dataInputStream.readFully(docData.rawData);
        }
        c = dataInputStream.readInt();
        if(c>0) {
            docData.attachments = new byte[c];
            dataInputStream.readFully(docData.attachments);
        }
        return docData;
    }

    /**
     *
     * @param storageManager
     * @param docData
     * @return
     * @throws Exception
     */
    public static Identifier write(StorageManager storageManager, DocRaw docData) throws Exception {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        DataOutputStream   dataOutputStream = new DataOutputStream(byteArrayOutputStream);
        int c = docData.getRawData()==null?0: docData.getRawData().length;
        dataOutputStream.writeInt(c);
        if(c>0){
            dataOutputStream.write(docData.rawData);
        }
        c = docData.getAttachments()==null? 0:docData.getAttachments().length;
        dataOutputStream.writeInt(c);
        if(c>0){
            dataOutputStream.write(docData.attachments);
        }
        dataOutputStream.flush();
        byteArrayOutputStream.flush();
        byte [] bs = byteArrayOutputStream.toByteArray();
        storageManager.storeByteArray(docData.internalIdentifier,bs);
        return docData.getInternalIdentifier();
    }

    /**
     *
     * @param storageManager
     * @param docData
     * @return
     * @throws IOException
     */
    public static boolean delete(StorageManager storageManager, DocRaw docData) throws IOException {
        storageManager.delete(docData.getInternalIdentifier().longValue());
        return true;
    }

    public void setInternalIdentifier(Identifier identifier){
        if(this.internalIdentifier==null)
            this.internalIdentifier=Identifier.create();
        this.internalIdentifier.copyFrom(identifier);
    }

    public Identifier getInternalIdentifier(){
        return this.internalIdentifier;
    }

    public void setRawData(byte[] rd){
        this.rawData = rd;
    }

    public byte[] getRawData(){
        return this.rawData;
    }

    public void setAttachments(byte[] at){
        this.attachments = at;
    }

    public byte[] getAttachments(){
        return this.attachments;
    }

    @Override
    public Object clone() {
        DocRaw docData = null;
        try {
            docData = new DocRaw();
            docData.internalIdentifier.copyFrom(this.internalIdentifier);
            if(this.rawData!=null)
                docData.rawData = Arrays.copyOf(this.rawData,this.rawData.length);
            if(this.attachments!=null)
                docData.attachments = Arrays.copyOf(this.attachments,this.attachments.length);
            return docData;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public boolean load(DataInput dataInput) throws IOException {
        if(internalIdentifier==null)
            internalIdentifier=Identifier.create();
        internalIdentifier.load(dataInput);
        int c = dataInput.readInt();
        if(c>0){
            rawData = new byte[c];
            dataInput.readFully(rawData);
        }
        c = dataInput.readInt();
        if(c>0){
            attachments = new byte[c];
            dataInput.readFully(attachments);
        }
        return true;
    }

    @Override
    public boolean store(DataOutput dataOutput) throws IOException {
        internalIdentifier.store(dataOutput);
        int c = rawData==null?0: rawData.length;
        dataOutput.writeInt(c);
        if(c>0)
            dataOutput.write(rawData);
        c = attachments==null? 0:attachments.length;
        dataOutput.writeInt(c);
        if(c>0)
            dataOutput.write(attachments);
        return true;
    }
}
